package controller;

import dao.repository.FilesRepository;
import domain.EccezioneUpdater;
import domain.File;
import domain.Root;
import domain.TipoLinkIn;
import gui.FilesView;
import gui.GUIUtils;
import gui.MainView;
import gui.UpdaterCellRenderer;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultListModel;
import javax.swing.JList;

public class FilesController {

    private static FilesController instance = new FilesController();
    private static Collection<File> allFiles = new HashSet<File>();
    private static ArrayList<File> filesInDB = new ArrayList<File>();
    private static ArrayList<File> filesInFS = new ArrayList<File>();
    private static Collection<File> unmodifiedFiles = new ArrayList<File>();
    private static Collection<File> newFiles = new ArrayList<File>();
    private static Collection<File> updatedFiles = new ArrayList<File>();
    private static Collection<File> deletedFiles = new ArrayList<File>();
    private static Root root = null;

    private FilesController() {
    }

    public static FilesController getInstance() {
        return instance;
    }
    private FilesView view;

    public void setView(FilesView view) {
        this.view = view;
        JList includedList = view.getIncludedList();
        JList excludedList = view.getExcludedList();
        includedList.setCellRenderer(new UpdaterCellRenderer());
        excludedList.setCellRenderer(new UpdaterCellRenderer());
    }

    public void fillFiles(Root root) {
        this.root = root;
        try {
            filesInDB.clear();
            filesInFS.clear();
            filesInDB = new ArrayList<File>(FilesRepository.findFilesByRoot(root));
            filesInFS = new ArrayList<File>(getAllFilesIn(root, root.getPath()));

            identifyFiles();
            
            for(File f : allFiles){
                if(f.isIncluso())
                    view.getIncludedFilesModel().addElement(f);
                else
                    view.getExcludedFilesModel().addElement(f);
            }
        } catch (EccezioneUpdater ex) {
            GUIUtils.showError(ex.getMessage());
        }
    }

    public void shiftFiles(DefaultListModel source, DefaultListModel destination, Object[] selectedValues) {
        for(Object o : selectedValues){
            File f = (File) o;
            f.setIncluso(!f.isIncluso());
            source.removeElement(f);
            destination.addElement(f);
        }
        MainView.getInstance().repaint();
        MainView.getInstance().validate();
        
    }

    public void commit() {
        /* Per il debug
        System.out.println("File non modificati: " + unmodifiedFiles);
        System.out.println("File nuovi: " + newFiles);
        System.out.println("File aggiornati: " + updatedFiles);
        System.out.println("File cancellati: " + deletedFiles);
        */
        try {
            for (File file : updatedFiles) {
                file.updateOnDB();
            }
            
            for(File file : unmodifiedFiles){
                file.updateOnDB();
            }

            for (File file : deletedFiles) {
                file.deleteFromDB();
            }

            for (File file : newFiles) {
                file.createOnDB();
            }
            GUIUtils.showMessage("Operazione completata con successo.");
        } catch (EccezioneUpdater ex) {
            GUIUtils.showError(ex.getMessage());
        }
    }

    private Collection<File> getAllFilesIn(final Root root, String path) {
        java.io.File file = new java.io.File(path);
        if (file.isFile()) {
            Collection<File> temp = new ArrayList<File>();
            File f = new File();
            try {
                f.setPath_file(file.getCanonicalPath()).
                        setIncluso(true).
                        setUltima_modifica(file.lastModified()).
                        inserisciLinkIn(new TipoLinkIn(root, f));
            } catch (IOException ex) {
                Logger.getLogger(FilesController.class.getName()).log(Level.SEVERE, null, ex);
            }
            temp.add(f);
            return temp;
        } else if (file.isDirectory()) {
            Collection<File> temp = new ArrayList<File>();
            java.io.File[] list = file.listFiles();
            for (java.io.File file2 : list) {
                try {
                    temp.addAll(getAllFilesIn(root, file2.getCanonicalPath()));
                } catch (IOException ex) {
                    Logger.getLogger(FilesController.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
                
            return temp;
        }
        throw new RuntimeException(file.toString() + "non e' un file, nè una directory");
    }

    private void identifyFiles() {
        allFiles.addAll(filesInDB);
        allFiles.addAll(filesInFS);
        for (File file : allFiles) {
            if (filesInDB.contains(file) && filesInFS.contains(file)) {
                if (filesInDB.get(filesInDB.indexOf(file)).getUltima_modifica() < filesInFS.get(filesInFS.indexOf(file)).getUltima_modifica()) {
                    file.setUltima_modifica(filesInFS.get(filesInFS.indexOf(file)).getUltima_modifica());
                    updatedFiles.add(file);
                } else {
                    unmodifiedFiles.add(file);
                }
            } else if (filesInDB.contains(file)) {
                deletedFiles.add(file);
            } else {
                newFiles.add(file);
            }
        }
    }

    public Collection<File> getUpdatedFiles() {
        return Collections.unmodifiableCollection(updatedFiles);
    }
    
    public Collection<File> getDeletedFiles() {
        return Collections.unmodifiableCollection(deletedFiles);
    }
    
    public Collection<File> getNewFiles() {
        return Collections.unmodifiableCollection(newFiles);
    }
}
